/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_expression.h                                                       *
 ****************************************************************************/

/**
 * @file elisa_expression.h
 * @brief Base classes for expressions.
 */

#ifndef _elisa_expression_h_
#define _elisa_expression_h_

#include "elisa_defs.h"
#include "elisa_variable.h"
#include <ostream>
#include <stdlib.h>
#include <string>


NAMESPACE_ELISA
// forward declaration
class SymbolicExpression;

/**
 * @ingroup Expression
 * @class SymbolicExpressionRep
 * @brief Base class for expression representation
 */
class SymbolicExpressionRep
{
public:
	/**
 	 * Constructors
 	 */
	SymbolicExpressionRep()
	{
		_nref = 0;
	}

	/**
 	 * Destructor
 	 */
	virtual ~SymbolicExpressionRep()
	{
	}

	/// @name Management of reference counter
	//@{
	/// Increases the reference counter
	int addRef();

	/// Decreases the reference counter
	int delRef();

	/// Returns the value of the reference counter
	int ref() const;
	//@}

	/**
 	 * @brief print the variable into the stream o
 	 * @param o the stream
 	 */
	virtual void print(std::ostream & o) const = 0;

	/**
 	 * @brief compute all variables of the expression in a set
 	 * @param s set where variables are putten
 	 */
	virtual void toVariables(VarImplSet & s) = 0;

	/**
 	 * @brief init the Intenal Representation of the variables
 	 * @param st SearchTree
 	 */
	virtual void initVariableImplementation(SearchTree & searchTree) = 0;

	/**
 	 * Returns the number of occurrences of v in the expression
 	 * @param v the variable which we want the multiplicity
 	 * @return the multiplicity of v
 	 */
	virtual int multiplicity(VariableImpl & v) = 0;

protected:
	/// Reference counter
	int _nref;

private:
	// copy protection
	SymbolicExpressionRep(const SymbolicExpressionRep & right)
	{
	}
	SymbolicExpressionRep & operator=(const SymbolicExpressionRep & right)
	{
	}
};

/**
 * @ingroup Expression
 * Symbolic view to an expression
 */
class SymbolicExpression
{
public:
	// @brief Constructor
	SymbolicExpression()
	{
	}

	// @brief Destructor
	virtual ~SymbolicExpression()
	{
	}

	/**
 	 * @brief print the variable into the stream o
 	 * @param o the stream
 	 */
	virtual void print(std::ostream & o) const
	{
		if (_expr != 0) {
			_expr->print(o);
		}
	};

	/**
 	 * @brief compute all variables of the expression in a set
 	 * @param s set where variables are putten
 	 */
	virtual void toVariables(VarImplSet & s) const
	{
		if (_expr != 0) {
			_expr->toVariables(s);
		}
	};

	/**
 	 * @brief init the Intenal Representation of the variables
 	 * @param st SearchTree
 	 */
	virtual void initVariableImplementation(SearchTree & searchTree)
	{
		if (_expr != 0) {
			_expr->initVariableImplementation(searchTree);
		}
	};

	/**
 	 * @brief Get the type of the expression
 	 */
	virtual std::string type() const = 0;

	/**
 	 * Returns the number of occurrences of v in the expression
 	 * @param v the variable which we want the multiplicity
 	 * @return the multiplicity of v
 	 */
	virtual int multiplicity(VariableImpl & v) const
	{
		if (_expr != 0) {
			return _expr->multiplicity(v);
		} else {
			return 0;
		}
	};

protected:
	//copy protection
	SymbolicExpression(const SymbolicExpression & right)
	{
	}
	SymbolicExpression & operator=(const SymbolicExpression & right)
	{
	}
	//@var internal representation used in algorithm
	SymbolicExpressionRep *_expr;
};
END_NAMESPACE_ELISA

/** @relates SymbolicExpression
 * @brief Output of expressions on a stream
 */
std::ostream &
operator<<(std::ostream & os,
           const elisa::SymbolicExpression & e);

#endif // ELISA_EXPRESSION_H
